using System.Collections.Generic;
using System.Xml.Serialization;
using System.Text;
using System;
using System.IO;

namespace usm.SolDev.Common.Config
{
    [Serializable]
    public class Configuration
    {
        #region Private fields
        private string configFolder = "";
        private ObjectState state = ObjectState.Original;
        private string applicationPath = "";
        #endregion

        #region Public properties
        /// <summary>
        /// Gets or sets the current state of the object
        /// </summary>
        [XmlIgnore()]
        public ObjectState State
        {
            get { return state; }
            set { state = value; }
        }

        /// <summary>
        ///     The folder where application has been started
        /// </summary>
        public string ApplicationPath
        {
            get { return applicationPath; }
            set { applicationPath = value; }
        }

        /// <summary>
        ///     The folder where configuration is stored
        /// </summary>
        public string ConfigFolder
        {
            get { return configFolder; }
            set { configFolder = value; }
        }
        
        #endregion

        #region C'tors
        /// <summary>
        ///     Default constructor
        /// </summary>
        public Configuration ()
        {
            configFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData);
            applicationPath = System.Environment.CurrentDirectory;
            CheckRequiredFolders();
        }

        /// <summary>
        ///     initialization constructor
        /// </summary>
        /// <param name="configFolder"></param>
        public Configuration (string newConfigFolder)
        {
            configFolder = newConfigFolder;
            CheckRequiredFolders();
        }
        #endregion

        #region Helper methods
        /// <summary>
        ///     Check required folders (in app folder)
        /// </summary>
        private void CheckRequiredFolders()
        {
            string appSettingsFolder = String.Format("{0}\\SolDev\\", configFolder);
            if (Directory.Exists(appSettingsFolder) == false)
            {
                Directory.CreateDirectory(appSettingsFolder);
            }

            configFolder = appSettingsFolder;
        }
        #endregion

        #region File I/O
        /// <summary>
        ///     Load's settings from user configuration folder. The file name
        /// is generated from object name and ".xml" extension appended.
        /// </summary>
        /// <param name="obj">object state restore</param>
        /// <note>can be ovveriden to achieve more flexibility</note>
        public virtual object LoadFromFile(object obj)
        {
            TextReader textReader = null;

            try
            {
                Type type = obj.GetType();
                XmlSerializer xmlSerializer = new XmlSerializer(type);
                textReader = new StreamReader(String.Format("{0}\\{1}.xml", configFolder, obj.ToString()));
                return xmlSerializer.Deserialize(textReader);
            }
            catch (Exception ex)
            {
                throw new SolDevException(SolDevExceptionKey.CannotLoadSettings, ex);
            }
            finally
            {
                if (textReader != null)
                {
                    textReader.Close();
                }
            }
        }

        /// <summary>
        ///     Load's settings from user configuration folder. The file name
        /// is generated from this name and ".xml" extension appended.
        /// </summary>
        /// <note>can be ovveriden to achieve more flexibility</note>
        public virtual object LoadFromFile()
        {
            TextReader textReader = null;

            try
            {
                Type type = this.GetType();
                XmlSerializer xmlSerializer = new XmlSerializer(type);

                if (File.Exists(String.Format("{0}\\{1}.xml", configFolder, this.ToString())))
                {
                    textReader = new StreamReader(String.Format("{0}\\{1}.xml", configFolder, this.ToString()));
                    return xmlSerializer.Deserialize(textReader);
                }
                else
                {
                    SaveToFile();
                }
            }
            catch (Exception /*ex*/)
            {
                
                //throw new SolDevException(SolDevExceptionKey.CannotLoadSettings, ex);
            }
            finally
            {
                if (textReader != null)
                {
                    textReader.Close();
                }
            }
            return this;
        }

        /// <summary>
        ///     Load's settings from specified file
        /// </summary>
        /// <note>can be ovveriden to achieve more flexibility</note>
        public virtual object LoadFromFile(string path)
        {
            TextReader textReader = null;

            try
            {
                Type type = this.GetType();
                XmlSerializer xmlSerializer = new XmlSerializer(type);

                if (File.Exists(path))
                {
                    textReader = new StreamReader(path);
                    return xmlSerializer.Deserialize(textReader);
                }
            }
            catch
            {
                SaveToFile();
            }
            finally
            {
                if (textReader != null)
                {
                    textReader.Close();
                }
            }
            return this;
        }

        /// <summary>
        ///     Save object state (settings) to file in configuration folder.
        /// The file name is generated from object name and ".xml" 
        /// extension appended.
        /// </summary>
        /// <param name="obj"></param>
        public virtual void SaveToFile(object obj)
        {
            TextWriter textWriter = null;

            try
            {
                Type type = obj.GetType();
                XmlSerializer xmlSerializer = new XmlSerializer(type);
                textWriter = new StreamWriter(String.Format("{0}\\{1}.xml", configFolder, obj.ToString()));
                xmlSerializer.Serialize(textWriter, obj);
            }
            catch (Exception ex)
            {
                SaveToFile();
                throw new SolDevException(SolDevExceptionKey.CannotSaveSettings, ex);
            }
            finally
            {
                if (textWriter != null)
                {
                    textWriter.Close();
                }
            }
        }

        /// <summary>
        ///     Save instance state (settings) to file in configuration folder.
        /// The file name is generated from instance object name and ".xml" 
        /// extension appended.
        /// </summary>
        public virtual void SaveToFile()
        {
            TextWriter textWriter = null;

            try
            {
                Type type = this.GetType();
                XmlSerializer xmlSerializer = new XmlSerializer(type);
                textWriter = new StreamWriter(String.Format("{0}\\{1}.xml", configFolder, this.ToString()));
                xmlSerializer.Serialize(textWriter, this);
            }
            catch (Exception ex)
            {
                SaveToFile();
                throw new SolDevException(SolDevExceptionKey.CannotSaveSettings, ex);
            }
            finally
            {
                if (textWriter != null)
                {
                    textWriter.Close();
                }
            }
        }

        /// <summary>
        ///     Save instance state to specified file.
        /// </summary>
        public virtual void SaveToFile(string path)
        {
            TextWriter textWriter = null;

            try
            {
                Type type = this.GetType();
                XmlSerializer xmlSerializer = new XmlSerializer(type);
                textWriter = new StreamWriter(path);
                xmlSerializer.Serialize(textWriter, this);
            }
            catch (Exception ex)
            {
                throw new SolDevException(SolDevExceptionKey.CannotSaveSettings, ex);
            }
            finally
            {
                if (textWriter != null)
                {
                    textWriter.Close();
                }
            }
        }
        #endregion
    }

    #region Object states
    /// <summary>
    ///     Object state constants
    /// </summary>
    [Serializable]
    public enum ObjectState : int
    {
        Original = 0,   // not modified
        New = 1,        // newly created
        Modified = 2,   // modified
        Deleted = 3     // deleted
    }
    #endregion
}
